﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SWCInvoice.Servicelayer;
using System.IO;

using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using System.Collections.ObjectModel;
using Cyotek.GhostScript.PdfConversion;


namespace SWCInvoice.Model {
    public class Document : ModelBase, IDisposable {

        #region Fields

        /// <summary>
        /// Filename of the document
        /// </summary>
        private string _fileName;
        /// <summary>
        /// Path of the document
        /// </summary>
        private string _filePath;
        ///// <summary>
        ///// Full filepath of the document
        ///// </summary>
        //private string _fullFilePath;
        /// <summary>
        /// ID of the document
        /// </summary>
        private string _id;
        /// <summary>
        /// Identifier of the document
        /// </summary>
        private string _identifier;
        /// <summary>
        /// Is the this the original document
        /// </summary>
        private bool _isOriginal;
        /// <summary>
        /// Is the this the a merged document
        /// </summary>
        private bool _isMerged;
        /// <summary>
        /// Is the this the a plain document
        /// </summary>
        private bool _isPlain;
        /// <summary>
        /// Is the this document read only
        /// </summary>
        private bool _readOnly;
        /// <summary>
        /// Name of the document path (result)
        /// </summary>
        private string _documentPathName;
        /// <summary>
        /// Name of the document
        /// </summary>        
        private string _documentName;
        /// <summary>
        /// Sort identifier of the document
        /// </summary>
        private string _sortIdentifier;
        ///// <summary>
        ///// Number of pages of the document
        ///// </summary>
        //private int _pageCount;
        /// <summary>
        /// PDF to Image Converter 
        /// </summary>
        Pdf2Image _pdf2Image;
        /// <summary>
        /// List of pages of the document
        /// </summary>
        private ObservableCollection<Page> _pages;
        /// <summary>
        /// The associated VirtualDocumentStructure
        /// </summary>
        private VirtualDocumentStructure _virtualDocumentStructure;

        private bool isDisposed = false;
        #endregion

        #region Constructor

        /// <summary>
        /// Constructor of the document object
        /// </summary>
        /// <param name="filenName">Name of the PDF file</param>
        /// <param name="name">Name of the document</param>
        public Document(VirtualDocumentStructure vds, string name = "Original") {
            _virtualDocumentStructure = vds;
            _id = Utilities.NewGuid();
            _documentName = name;
            _isOriginal = false;
            _readOnly = false;

            FileInfo fileInfo = new FileInfo(vds.FullFileName);
            _fileName = fileInfo.Name;
            _filePath = fileInfo.Directory.FullName;            
        }
        #endregion

        #region Properties

        /// <summary>
        /// ID of the document
        /// </summary>
        /// <value>A GUID value</value>
        public string ID {
            get {
                return _id;
            }
        }

        /// <summary>
        /// Is the this the original document
        /// </summary>
        public bool IsOriginal {
            get {
                return _isOriginal;
            }
            set {
                if (_isOriginal == value)
                    return;
                _isOriginal = value;
                RaisePropertyChanged("IsOriginal");
            }
        }

        /// <summary>
        /// Is the this the a merged document
        /// </summary>
        public bool IsMerged
        {
            get
            {
                return _isMerged;
            }
            set
            {
                if (_isMerged == value)
                    return;
                _isMerged = value;
                RaisePropertyChanged("IsMerged");
            }
        }

        /// <summary>
        /// Is the this the a plain document
        /// </summary>
        public bool IsPlain
        {
            get
            {
                return _isPlain;
            }
            set
            {
                if (_isPlain == value)
                    return;
                _isPlain = value;
                RaisePropertyChanged("IsPlain");
            }
        }

        /// <summary>
        /// Is the this document read only
        /// </summary>
        public bool ReadOnly {
            get {
                return _readOnly;
            }
            set {
                if (_readOnly == value)
                    return;
                _readOnly = value;
                RaisePropertyChanged("ReadOnly");
            }
        }

        /// <summary>
        /// Name of the document path (result)
        /// </summary>
        public string DocumentPathName
        {
            get
            {
                return _documentPathName;
            }
            set
            {
                if (_documentPathName == value)
                    return;
                _documentPathName = value;
                RaisePropertyChanged("DocumentPathName");
            }
        }

        /// <summary>
        /// Name of the document
        /// </summary>
        public string DocumentName {
            get {
                return _documentName;
            }
            set {
                if (_documentName == value)
                    return;
                _documentName = value;
                RaisePropertyChanged("DocumentName");
            }
        }

        /// <summary>
        /// Sort identifier of the document 
        /// </summary>
        public string SortIdentifier {
            get {
                return _sortIdentifier;
            }
            set {
                if (_sortIdentifier == value)
                    return;
                _sortIdentifier = value;
                RaisePropertyChanged("SortIdentifier");
            }
        }

        /// <summary>
        /// List of pages of the document
        /// </summary>
        public ObservableCollection<Page> Pages {
            get {
                if (_pages == null)
                    _pages = new ObservableCollection<Page>();
                return _pages;
            }
            set {
                if (_pages == value)
                    return;
                _pages = value;
                RaisePropertyChanged("Pages");
            }
        }

        /// <summary>
        /// Identifier of the document
        /// </summary>
        public string Identifier {
            get {
                return _identifier;
            }
            set {
                if (_identifier == value)
                    return;
                _identifier = value;
                RaisePropertyChanged("Identifier");
            }
        }
           
        /// <summary>
        /// Number of pages of the document
        /// </summary>
        public int PageCount {
            get {
                if (_pages != null)
                    return _pages.Count;
                else
                    return 0;
            }
        }

        /// <summary>
        /// Filename of the document
        /// </summary>
        public string FileName {
            get {
                return _fileName;
            }
            set {
                if (_fileName == value)
                    return;
                _fileName = value;
                RaisePropertyChanged("FileName");
            }
        }

        /// <summary>
        /// Path of the document
        /// </summary>
        public string FilePath {
            get {
                return _filePath;
            }
            set {
                if (_filePath == value)
                    return;
                _filePath = value;
                RaisePropertyChanged("FilePath");
            }
        }

        /// <summary>
        /// Full filepath of the document
        /// </summary>
        public string FullFilePath {
            get {
                return string.Format("{0}\\{1}", _filePath, _fileName);
            }
        }

        /// <summary>
        /// PDF to Image Converter
        /// </summary>
        public Pdf2Image Pdf2Image {
            get {
                if (_pdf2Image != null) {                    
                    return _pdf2Image;
                } else {
                    _pdf2Image = new Pdf2Image(this.FullFilePath, PDFHandler.GetPdf2ImageSettings());                                        
                    return _pdf2Image;
                }
            }
        }

        /// <summary>
        /// The associated VirtualDocumentStructure
        /// </summary>
        public VirtualDocumentStructure VirtualDocumentStructure {
            get {
                return _virtualDocumentStructure;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Add a empty page to a document
        /// </summary>
        /// <returns>true/false</returns>
        public bool AddEmptyPage() {
            bool result = false;
            try {
                Page page = null;
                iTextSharp.text.Document document = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4);

                MemoryStream memStream = new MemoryStream();
                PdfWriter pdfWriter = PdfWriter.GetInstance(document, memStream);

                pdfWriter.Open();
                document.Open();
                
                result = document.NewPage();
                document.Add(new iTextSharp.text.Paragraph(" "));
                
                document.Close();
                pdfWriter.Close();

                byte[] data = memStream.GetBuffer();
                memStream = new MemoryStream(data);

                PdfReader reader = new PdfReader(memStream);

                page = new Page(this);
                page.Content = PdfTextExtractor.GetTextFromPage(reader, 1);
                page.PageNumberOriginal = 0;
                page.PDFContent = pdfWriter.GetImportedPage(reader, 1);

                this.Pages.Add(page);
                document.Close();
                pdfWriter.Close();
                result = true;

            } catch (Exception ex) {
                result = false;                
            }
            
            return result;
        }

        #endregion

        #region Dispose

        protected void Dispose(bool disposing) {
            if (disposing) {
                // Code to dispose the managed resources of the class


                //FileName = null;
                //FilePath = null;

                //Identifier = null;
                //DocumentPathName = null;
                //DocumentName = null;
                _pdf2Image = null;

                foreach (Page item in Pages) {
                    item.Dispose();
                }
                //Pages = null;

                //VirtualDocumentStructure.Dispose();
            }

            // Code to dispose the un-managed resources of the class
            isDisposed = true;
        }

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
